package com.solrtest.service.impl;

import com.solrtest.doman.Product;
import com.solrtest.doman.Shop;
import com.solrtest.service.ProductService;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class ProductServiceImpl implements ProductService {

    private final SolrClient solrClient;
    private final String coreName = "wlx";  //查询时只指定一次 coreName 即可,但是新增、修改、删除的时候需要指定【操作】 和 【提交】 的 核心名 否则删除会报404错误

    @Autowired
    public ProductServiceImpl(SolrClient solrClient) {
        this.solrClient = solrClient;
    }


    @Override
    public void add(Product product) {
        SolrInputDocument document = new SolrInputDocument();
        document.setField("id", product.getId());
        document.setField("productName", product.getProductName());
        document.setField("productPrice", product.getProductPrice());
        document.setField("productSpec", product.getProductSpec());
        document.setField("createTime", product.getCreateTime());
        document.setField("isDel", product.getIsDel());
        try {
            solrClient.add(coreName, document);
            solrClient.commit(coreName);
        } catch (SolrServerException | IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void edit(Product product) {
        try {
            solrClient.addBean(coreName, product);
            solrClient.commit(coreName);
        } catch (IOException | SolrServerException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void del(String id) {
        try {
            solrClient.deleteById(coreName, id);
            solrClient.commit(coreName);
        } catch (SolrServerException | IOException e) {
            e.printStackTrace();
        }
    }


    @Override
    public List<Product> queryAll() {
        List<Product> bookList = new ArrayList<>();
        SolrQuery solrQuery = new SolrQuery();
        solrQuery.setQuery("*:*");
        try {
            QueryResponse queryResponse = solrClient.query(coreName, solrQuery);
            if (queryResponse != null) {
                bookList = queryResponse.getBeans(Product.class);
            }
        } catch (SolrServerException | IOException e) {
            e.printStackTrace();
        }
        return bookList;
    }


    @Override
    public List<Product> query(Product product) {
        List<Product> bookList = new ArrayList<>();
        SolrQuery solrQuery = new SolrQuery();

        //******************* (q)查询条件  必须  (一个核心下可以有多个实体，但是查询的时候 是不能指定实体去查询的，所以在建立实体的时候 最好标注个字段，用于查询时去过滤实体)
        //    Solr的检索运算符 https://www.cnblogs.com/cuihongyu3503319/p/9875628.html
        //符号	意义
        //“:” 	指定字段查指定值，如返回所有值:
        //“?” 	表示单个任意字符的通配
        //“*” 	表示多个任意字符的通配（不能在检索的项开始使用*或者?符号）
        //“~” 	表示模糊检索，如检索拼写类似于”roam”的项这样写：roam~将找到形如foam和roams的单词；roam~0.8，检索返回相似度在0.8以上的记录。
        //AND || 	布尔操作符
        //OR、&& 	布尔操作符
        //NOT、!、- 	（排除操作符不能单独与项使用构成查询）
        //“+” 	存在操作符，要求符号”+”后的项必须在文档相应的域中存在²
        //( ) 	用于构成子查询
        //[] 	包含范围检索，如检索某时间段记录，包含头尾，date:[201507 TO 201510]
        //{} 	不包含范围检索，如检索某时间段记录，不包含头尾date:{201507 TO 201510}

        // 1.查询所有
        //solrQuery.setQuery("*:*");

        // 2.拼接查询条件
        //solrQuery.setQuery("productName:" + product.getProductName());

        // 3.指定查询字段
        //solrQuery.setQuery(product.getProductName());
        //solrQuery.set("df", "productName");//指定搜索字段(和上面的组合使用)

        // 4.通过前缀设置条件
        //solrQuery.set("q", "productName:" + product.getProductName());

        //动态查询条件，这里的 AND 必须大写
        StringBuilder sb = new StringBuilder();
        if (!StringUtils.isEmpty(product.getProductName()))
            sb.append("productName:").append(product.getProductName());
        if (!StringUtils.isEmpty(product.getProductSpec()))
            if (sb.length() == 0)
                sb.append("productSpec:").append(product.getProductSpec());
            else
                sb.append(" AND ").append("productSpec:").append(product.getProductSpec());
        if (!StringUtils.isEmpty(product.getId()))
            if (sb.length() == 0)
                sb.append("id:").append(product.getId());
            else
                sb.append(" AND ").append("id:").append(product.getId());

        System.out.println("查询条件:" + sb);
        solrQuery.setQuery(sb.toString());

        //******************* (fq)过滤条件  可选(作用：在q查询符合结果中同时是fq查询符合的)
        // productPrice: [1-1000000] , 用 * 表示无限
        // productPrice: [100 TO *]  ,表示 productPrice 大于 100
        solrQuery.set("fq", "productPrice:[20 TO 100]"); //也可写成: solrQuery.setFilterQueries("item_price:[1 TO 1000000]");


        //******************* (fl) 指定返回那些字段内容，用逗号或空格分隔多个
        //相当于 solrQuery.setFields("id,item_title,item_price")；
        solrQuery.set("fl", "id,productName,productPrice");

        //******************* 设置高亮
        solrQuery.setHighlight(true);//设置高亮
        solrQuery.addHighlightField("productName");//设置高亮的字段
        solrQuery.setHighlightSimplePre("<em>"); //设置高亮前缀
        solrQuery.setHighlightSimplePost("</em>"); //设置高亮后缀


        //******************* 排序 可选
        solrQuery.setSort("id", SolrQuery.ORDER.desc);  //也可写成: solrQuery.set("sort"," id desc");
        //开始索引为0
        solrQuery.setStart(0); // 也可写成: solrQuery.set("start",0);
        //每页显示多少行
        solrQuery.setRows(10);// 也可写成:  solrParams.set("rows",2);

        try {
            QueryResponse queryResponse = solrClient.query(coreName, solrQuery);
            if (queryResponse != null) {

                //取高亮
                Map<String, Map<String, List<String>>> highlightingMap = queryResponse.getHighlighting();
                System.out.println(highlightingMap);
                //跟是否分页的设置无关，返回的是总的记录数
                System.out.println("总的查询数量:" + queryResponse.getResults().getNumFound());

                bookList = queryResponse.getBeans(Product.class);
            }
        } catch (SolrServerException | IOException e) {
            e.printStackTrace();
        }
        return bookList;
    }

    @Override
    public List<Shop> getByGps(String gps) {
        SolrQuery query = new SolrQuery();
        query.set("q", "*:*");
        query.set("fq", "{!geofilt}");          //距离过滤器
        query.set("d", "10");                   //距离 单位公里
        query.set("pt", gps);                   //参考点坐标   "39.939549858674226,116.82007871201711" [纬度,经度]
        query.set("sfield", "position");        //坐标字段
        query.set("start", "0");                //起始记录
        query.set("rows", "10");                //分页
        query.set("sort", "geodist() asc");     //排序规则
        query.set("fl", "*,distance:geodist()");//返回的距离 5.834996E-5  注意这个科学计数法坑爹的很，单位是千米
        //执行查询并且返回结果
        QueryResponse reponse = null;
        try {
            reponse = solrClient.query("jts", query);
            //获取匹配返回的结果
            SolrDocumentList list = reponse.getResults();
            for (SolrDocument doc : list)
                System.out.println(doc);
            //匹配结果总数
            long count = list.getNumFound();
            System.out.println("匹配结果总数:" + count);
            return reponse.getBeans(Shop.class);
        } catch (SolrServerException | IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        //科学计数转为数字
        BigDecimal bd = new BigDecimal("5.834996E-5");
        System.out.println(bd.toPlainString());
    }
}
